package nio.client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

/**
 * @author Huhailong
 * @Description time 客户端处理类
 * @Date 2021/4/9.
 */
public class TimeClientHandle implements Runnable{
    private final String host;
    private final int port;
    private Selector selector;
    private SocketChannel socketChannel;
    private volatile boolean stop;

    public TimeClientHandle(String host, int port) {
        this.host = host;
        this.port = port;
        try{
            selector = Selector.open();
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);

        }catch (IOException e){
            e.printStackTrace();
            System.exit(1);
        }
    }

    @Override
    public void run() {
        doConnect();
        while(!stop){
            try {
                selector.select(1000);
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                SelectionKey key;
                while(iterator.hasNext()){
                    key = iterator.next();
                    iterator.remove();
                    handleInput(key);
                }
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(1);
            }
        }
        if(selector != null){
            try {
                selector.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void handleInput(SelectionKey key) throws IOException {
        if(key.isValid()){
            //判断连接是否成功
            if(key.isConnectable()){
                if(socketChannel.finishConnect()){
                    socketChannel.register(selector,SelectionKey.OP_READ);
                    doWrite(socketChannel);
                }else{
                    System.out.println("连接失败");
                    System.exit(1);
                }
            }
            if(key.isReadable()){
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                /*
                 * read(ByteBuffer dst)方法：
                 * 从该管道读取到给定的缓冲区的字节序列，尝试从管道读取r个字节，其中r时缓冲区种剩余的字节数,即dst.remaining().
                 * 返回的结果为读取的字节数，可能为零，如果通道已到达流出端则为-1
                 */
                int readBytes = socketChannel.read(byteBuffer);
                if(readBytes>0){
                    byteBuffer.flip();
                    byte[]bytes = new byte[byteBuffer.remaining()];
                    byteBuffer.get(bytes);
                    String body = new String(bytes, StandardCharsets.UTF_8);
                    if("Bye!".equals(body)){
                        System.out.println("退出");
                        this.stop = true;
                        System.exit(1);
                    }
                    System.out.println("Now is : "+body);
                    doWrite(socketChannel);
                }else if(readBytes<0){
                    //链路关闭
                    key.cancel();
                    socketChannel.close();
                }
            }

        }
    }

    private void doConnect(){
        //如果直接连接成功，则注册到多路复用器上，发送请求消息，读取应答消息
        try {
            if(socketChannel.connect(new InetSocketAddress(host,port))){
                System.out.println("连接成功");
                socketChannel.register(selector, SelectionKey.OP_READ);
                doWrite(socketChannel);
            }else {
                System.out.println(socketChannel.isConnected());
                System.out.println(socketChannel.getRemoteAddress());
                System.out.println("首次握手失败,注册CONNECT操作位");
                socketChannel.register(selector, SelectionKey.OP_CONNECT);
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    private void doWrite(SocketChannel socketChannel) throws IOException {
        System.out.println("输入发送内容：");
        Scanner sc = new Scanner(System.in);
        String message = sc.nextLine();
        byte[] req = message.getBytes();
        ByteBuffer writeBuffer = ByteBuffer.allocate(req.length);
        writeBuffer.put(req);
        writeBuffer.flip();
        socketChannel.write(writeBuffer);
        if(!writeBuffer.hasRemaining()){
            System.out.println("Send order 2 server succeed. ");
        }
    }
}
